package pikasial.graphique;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.IOException;

import java.util.Collections;
import java.util.List;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JToolBar;
import javax.swing.WindowConstants;

import pikasial.images.ImageContainer;
import pikasial.images.ListeAlbums;
import pikasial.images.PhotosListModel;
import pikasial.images.PikImage;
import pikasial.images.traitements.RescaleTraitement;
//import sun.swing.ImageIconUIResource;

/**
 * Fenêtre dans laquelle une image est affichée.
 * <p>
 * Cette classe définit une nouvelle fenêtre affichée à chaque fois qu'une
 * image doit être affichée.
 * Il n'y a qu'une seule fenêtre pour visionner les images (pattern
 * singleton).
 *
 * @author ESIAL - Groupe 14
 */
@SuppressWarnings("serial")
public final class VisionneuseImage extends JFrame {

    /** L'instance en cours de la visionneuse. */
    private static final VisionneuseImage INSTANCE = new VisionneuseImage();

    /**
     * Accède à l'instance en cours.
     * @return instance en cours de la visionneuse d'image
     */
    public static VisionneuseImage getInstance() {
        return INSTANCE;
    }
    /** Le composant dans lequel est affiché l'image. */
    private JLabel jl;
    /** Le panneau qui contient l'image. */
    private JPanel paneImage;
    /** L'image à afficher dans la fenêtre. */
    private BufferedImage image;

    private JButton prec, suiv, zoomIn, zoomOut, zoomInit;

    private ImageContainer dossierParent;
    private int indexDansDossier;
    private PikImage pikImage;

    private int niveauZoom = 0;

    /** Construit l'instance de la fenêtre. */
    private VisionneuseImage() {
        super();
        setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE);
        paneImage = new JPanel(new BorderLayout());
        paneImage.setPreferredSize(new Dimension(PikasialFrame.LARGEUR_FENETRE,
            PikasialFrame.HAUTEUR_FENETRE));

        jl = new JLabel();
        jl.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);

        JScrollPane scrollPane = new JScrollPane();
        scrollPane.getViewport().add(jl);

        paneImage.add(scrollPane, BorderLayout.CENTER);

        JToolBar toolBar = new JToolBar();
        addButtons(toolBar);
        paneImage.add(toolBar, BorderLayout.SOUTH);

        setContentPane(paneImage);

        paneImage.addComponentListener(new ComponentListener() {

            public void componentHidden(final ComponentEvent arg0) {
            }

            public void componentMoved(final ComponentEvent arg0) {
            }

            public void componentResized(final ComponentEvent arg0) {
                if (image != null) {
                    jl.setIcon(new ImageIcon(rescaleImage(image)));
                }
            }

            public void componentShown(final ComponentEvent arg0) {
            }
        });

        pack();
    }

    private BufferedImage rescaleImage(BufferedImage bi) {
        double sc1,sc2;
        sc1 = ((double) jl.getWidth()) / bi.getWidth();
        sc2 = ((double) jl.getHeight()) / bi.getHeight();
        double sc = Math.min(sc1, sc2);
        if (sc < 1) {
        	RescaleTraitement rt = new RescaleTraitement(bi, sc, sc,RescaleTraitement.TYPE_BILINEAR);
            return rt.executeTraitement();
        } else {
            return bi;
        }
    }

    private void addButtons(JToolBar tb) {
        prec = new JButton();
        prec.setIcon(new ImageIcon(getClass().getResource(pikasial.utils.PikasialConstantes.PREVIOUS_ICON_PATH)));
        prec.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                if (indexDansDossier > 0) {
                    afficherImage(dossierParent.getImage(indexDansDossier - 1));
                }
            }
        });
        prec.setToolTipText("Image précèdente");
        tb.add(prec);

        suiv = new JButton();
        suiv.setIcon(new ImageIcon(getClass().getResource(pikasial.utils.PikasialConstantes.NEXT_ICON_PATH)));
        suiv.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                if (indexDansDossier < dossierParent.getImageCount() - 1) {
                    afficherImage(dossierParent.getImage(indexDansDossier + 1));
                }
            }
        });
        suiv.setToolTipText("Image suivante");
        tb.add(suiv);

        tb.addSeparator();

        zoomIn = new JButton();
        zoomIn.setIcon(new ImageIcon(getClass().getResource(pikasial.utils.PikasialConstantes.ZOOM_IN_ICON_PATH)));
        zoomIn.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                double rapportHL = ((double) image.getWidth()) / image.getHeight();

                double sc;
                if (rapportHL >= 1.0) {
                    sc = ((double) jl.getWidth()) / image.getWidth();
                } else {
                    sc = ((double) jl.getHeight()) / image.getHeight();
                }

                if (niveauZoom == 0 && (sc < 1)) {
                    niveauZoom++;
                } else {
                    niveauZoom++;
                    RescaleTraitement rt = new RescaleTraitement(image, 1.25, 1.25, AffineTransformOp.TYPE_BICUBIC);
                    image = rt.executeTraitement();
                }
                jl.setIcon(new ImageIcon(image));
                rafraichirBoutons();
            }
        });
        zoomIn.setToolTipText("Agrandir l'image de 25%");
        tb.add(zoomIn);

        zoomOut = new JButton();
        zoomOut.setIcon(new ImageIcon(getClass().getResource(pikasial.utils.PikasialConstantes.ZOOM_OUT_ICON_PATH)));
        zoomOut.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                double rapportHL = ((double) image.getWidth()) / image.getHeight();

                double sc;
                if (rapportHL >= 1.0) {
                    sc = ((double) jl.getWidth()) / image.getWidth();
                } else {
                    sc = ((double) jl.getHeight()) / image.getHeight();
                }

                if (niveauZoom == 1 && (sc < 1)) {
                    niveauZoom--;
                    jl.setIcon(new ImageIcon(rescaleImage(image))); //RescaleTraitement.rescaleToFitPanel(image,
                        //jl.getWidth(), jl.getHeight()));
                } else {
                    niveauZoom--;
                    RescaleTraitement rt = new RescaleTraitement(image, 0.75, 0.75, AffineTransformOp.TYPE_BICUBIC);
                    image = rt.executeTraitement();
                    jl.setIcon(new ImageIcon(image));
                }
                rafraichirBoutons();
            }
        });
        zoomOut.setToolTipText("Réduire l'image de 25%");
        tb.add(zoomOut);

        zoomInit = new JButton();
        zoomInit.setIcon(new ImageIcon(getClass().getResource(pikasial.utils.PikasialConstantes.ZOOM_INIT_ICON_PATH)));
        zoomInit.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                try {
                    image = pikImage.getImage();
                } catch (IOException e) {
                    if (niveauZoom < 0) {
                        while (niveauZoom != 0) {
                            niveauZoom++;
                            RescaleTraitement rt = new RescaleTraitement(image, 1.25, 1.25);
                            image = rt.executeTraitement();
                        }
                    } else if (niveauZoom > 0) {
                        while (niveauZoom != 0) {
                            niveauZoom--;
                            RescaleTraitement rt = new RescaleTraitement(image, 0.75, 0.75);
                            image = rt.executeTraitement();
                        }
                    }
                }
                jl.setIcon(new ImageIcon(rescaleImage(image)));//RescaleTraitement.rescaleToFitPanel(image,
                        //jl.getWidth(), jl.getHeight()));
                niveauZoom = 0;
                rafraichirBoutons();
            }
        });
        zoomInit.setToolTipText("Revenir à la taille initiale");
        tb.add(zoomInit);
    }

    private void rafraichirBoutons() {
        if (niveauZoom == 7) {
            zoomIn.setEnabled(false);
            zoomOut.setEnabled(true);
        } else if (niveauZoom == -5) {
            zoomIn.setEnabled(true);
            zoomOut.setEnabled(false);
        } else {
            zoomIn.setEnabled(true);
            zoomOut.setEnabled(true);
        }

        if (indexDansDossier == 0) {
            prec.setEnabled(false);
            suiv.setEnabled(true);
        } else if (indexDansDossier == dossierParent.getImageCount() -1) {
            prec.setEnabled(true);
            suiv.setEnabled(false);
        } else {
            prec.setEnabled(true);
            suiv.setEnabled(true);
        }
    }
    /**
     * Affiche l'image donnée en paramètre dans la fenêtre.
     * @param pikim - l'image à afficher
     */
    public void afficherImage(final pikasial.images.PikImage pikim) {
        try {
            pikImage = pikim;
            image = pikim.getImage();
        } catch (IOException e) {
            JOptionPane.showMessageDialog(this,
                "Erreur lors du chargement de l'image !", "Erreur !",
                JOptionPane.ERROR_MESSAGE);
        }

        jl.setIcon(new ImageIcon(rescaleImage(image)));//RescaleTraitement.rescaleToFitPanel(image,
            //jl.getWidth(), jl.getHeight()));

        dossierParent = ListeAlbums.getInstance().getAlbumAffiche();
        Collections.sort((List<PikImage>) dossierParent.getAllImages(), PhotosListModel.PAR_CHEMIN);

        for (int i = 0; i < dossierParent.getImageCount(); i++) {
            if (dossierParent.getImage(i).equals(pikImage)) {
               indexDansDossier = i;
            }
        }

        rafraichirBoutons();

        setTitle(pikim.getName());
        setVisible(true);
    }
}
